/*
 * Copyright (c) 2023 HPMicro
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *
 */

#include <stdio.h>
#include "board.h"
#include "hpm_sysctl_drv.h"
#include "hpm_gptmr_drv.h"
#include "hpm_gpio_drv.h"
#include "hpm_gpiom_drv.h"
#include "hpm_debug_console.h"
#include "hpm_gptmr_drv.h"
#include "hpm_dmamux_drv.h"
#include "hpm_dma_drv.h"
#include "hpm_synt_drv.h"

#include "hpm_trgm_drv.h"
#include "hpm_pwm_drv.h"

#define  US 30000

#define APP_BOARD_GPTMR               HPM_GPTMR4
#define BOARD_GPTMR_CH0               0
#define BOARD_GPTMR_CH1               BOARD_GPTMR_CHANNEL
#define APP_BOARD_GPTMR_CLOCK         clock_gptmr4

#define APP_GPTMR_DMA                 BOARD_APP_HDMA
#define APP_GPTMR_DMA_IRQ             BOARD_APP_HDMA_IRQ

#define APP_DMA_CH0                    (0U)
#define APP_DMA_CH1                    (1U)
#define APP_DMAMUX_CH0                 DMA_SOC_CHN_TO_DMAMUX_CHN(APP_GPTMR_DMA, APP_DMA_CH0)
#define APP_DMAMUX_CH1                 DMA_SOC_CHN_TO_DMAMUX_CHN(APP_GPTMR_DMA, APP_DMA_CH1)

static void dma_transfer_config(void);

ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(4) uint32_t gpio_read_data[4096] = {0};
ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(4) uint32_t gpio_read_test = 0x10000010;

ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(4) uint32_t gpio_write_data[4096] = {0};
ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(4) uint32_t gpio_write_test = 0;

volatile bool     ch0_dma_is_done;
volatile bool     ch1_dma_is_done;

static bool pwm_output_over = false;

dma_channel_config_t ch1_config = {0};
dma_channel_config_t ch0_config = {0};


void isr_dma(void)
{
    volatile hpm_stat_t stat;
    stat = dma_check_transfer_status(APP_GPTMR_DMA, APP_DMA_CH0);
    if (stat & DMA_CHANNEL_STATUS_TC) {
        ch0_dma_is_done = true;
    }
}
SDK_DECLARE_EXT_ISR_M(APP_GPTMR_DMA_IRQ, isr_dma)

volatile uint32_t gptmr_freq;

void start_measure(void)
{
    dma_disable_channel(APP_GPTMR_DMA, APP_DMA_CH0);
    dma_disable_channel(APP_GPTMR_DMA, APP_DMA_CH1);

    dma_reset(APP_GPTMR_DMA);
    memset(gpio_read_data,0x00,sizeof(gpio_read_data));

    dma_setup_channel(APP_GPTMR_DMA, APP_DMA_CH0, &ch1_config, false);
    dma_setup_channel(APP_GPTMR_DMA, APP_DMA_CH1, &ch0_config, false);

    dma_enable_channel(APP_GPTMR_DMA, APP_DMA_CH0);
    dma_enable_channel(APP_GPTMR_DMA, APP_DMA_CH1);
}


void GPIO_Read_Data_Clean(uint8_t bit_num)
{
    uint32_t mask = 1 << bit_num;
    for(uint32_t i = 0;i<4096;i++)
    {
        gpio_read_data[i] &= mask;
    }
}

static inline void gpio_enable_port_input_with_mask(GPIO_Type *ptr, uint32_t port, uint32_t mask)
{
    ptr->OE[port].VALUE = ~mask;
}

/* 以下是生成PWM的代码↓ */
void init_trigger_source(PWM_Type *ptr,uint32_t freq,uint8_t channel)
{
    uint8_t cmp_index = 0;
    uint32_t reload = 0;
    pwm_cmp_config_t cmp_config[2] = {0};
    pwm_config_t pwm_config = {0};

    /* 33.33KHz reload at 200MHz */ //默认未经修改的PWM时钟频率是200MHz
    reload = (200000000 / freq ) - 1;
    printf("reload = %d \r\n",reload);
    pwm_set_reload(ptr, 0, reload);

    pwm_fault_source_config_t fault_config = {0};

    pwm_stop_counter(ptr);
    pwm_get_default_pwm_config(ptr, &pwm_config);

    pwm_config.enable_output = true;
    pwm_config.dead_zone_in_half_cycle = 0;
    pwm_config.invert_output = false;
    pwm_config.fault_mode = pwm_fault_mode_force_output_0;
    pwm_config.fault_recovery_trigger = pwm_fault_recovery_immediately;/* 软件复位后，停止输出 */

    fault_config.source_mask = pwm_fault_source_internal_0;
    pwm_config_fault_source(ptr, &fault_config);

    pwm_enable_dma_request(ptr, PWM_IRQ_CMP(1));
    
    trgm_dma_request_config(HPM_TRGM2, 0, HPM_TRGM2_DMA_SRC_PWM2_CMP1); /* TRGM: 互联管理器 */
    dmamux_config(BOARD_APP_DMAMUX, APP_DMAMUX_CH0, HPM_DMA_SRC_MOT2_0, true);

    /*
     * reload and start counter
     */
    
    pwm_set_start_count(ptr, 0, 0);

    /*
     * config cmp = RELOAD + 1
     */
    pwm_enable_reload_at_synci(ptr);//允许时钟同步

    cmp_config[0].mode = pwm_cmp_mode_output_compare;
    cmp_config[0].update_trigger = pwm_shadow_register_update_on_modify;
    cmp_config[0].cmp = reload >> 1;
    /*
     * config pwm as reference
     */
    if (status_success != pwm_setup_waveform(ptr, 1, &pwm_config, cmp_index + 1, &cmp_config[0], 1)) {
        printf("failed to setup waveform\n");
        while(1);
    }
   
    
    pwm_issue_shadow_register_lock_event(ptr);
}

void init_trigger_mux(TRGM_Type * ptr)
{
    trgm_output_t trgm_output_cfg;

    trgm_output_cfg.invert = false;
    trgm_output_cfg.type = trgm_output_same_as_input;

    HPM_IOC->PAD[IOC_PAD_PD25].FUNC_CTL = IOC_PD25_FUNC_CTL_TRGM2_P_08;
    HPM_IOC->PAD[IOC_PAD_PD16].FUNC_CTL = IOC_PD16_FUNC_CTL_TRGM2_P_06;

    trgm_enable_io_output(HPM_TRGM2, 1 << 8);

    //trgm_output_cfg.input  = HPM_TRGM2_INPUT_SRC_PWM2_CH8REF;
    //trgm_output_config(ptr, HPM_TRGM2_OUTPUT_SRC_TRGM2_P8, &trgm_output_cfg);

    trgm_output_cfg.input  = HPM_TRGM2_INPUT_SRC_GPTMR5_OUT2;
    trgm_output_config(ptr, HPM_TRGM2_OUTPUT_SRC_PWM2_FAULTI0,&trgm_output_cfg);

    trgm_output_cfg.input = HPM_TRGM2_INPUT_SRC_GPTMR5_OUT2;
    trgm_output_config(ptr, HPM_TRGM2_OUTPUT_SRC_PWM2_SYNCI,&trgm_output_cfg);
}

void timer_config_us(GPTMR_Type * GPTMR,uint8_t ch_index,uint32_t priority,uint16_t us);

int main(void)
{
    board_init();

    dma_transfer_config();
    init_pwm_pins(HPM_PWM2);
    init_trigger_mux(HPM_TRGM2);/*同时也将PWM2的CHREF8转到IO输出，方便参考*/

    gpio_enable_port_input_with_mask(HPM_GPIO0,GPIO_OE_GPIOE,0xffffffff);

    while (1) {
        printf("please press any key to start PWM measure\r\n");
        getchar();

        init_trigger_source(HPM_PWM2,30000000,0);/* PD25 20K */ /* 计算出来的频率为33.3333Mhz */
        
        timer_config_us(HPM_GPTMR5,2,4,60);/* 输出波形的时长为30us,为1000个波形*/

        start_measure();

        pwm_start_counter(HPM_PWM2);

        gptmr_start_counter(HPM_GPTMR5,2);

        while (1) {
            if(ch0_dma_is_done /*||  pwm_output_over*/)//PWM输出完成后查看DMA搬运的数据
            {
                pwm_output_over = false;
                ch0_dma_is_done = false;

                GPIO_Read_Data_Clean(28);
                
                break;/* debug模式下，在此时打断点观察数据 */
            }
        }
    }
    return 0;
}


#if (defined (DMA_SOC_MAX_COUNT) && (DMA_SOC_MAX_COUNT == 2)) && (defined (CONFIG_USE_DMA) && (CONFIG_USE_DMA == 1))
static void dma_transfer_config(void)
{
    dma_disable_channel(APP_GPTMR_DMA, APP_DMA_CH0);
    dma_disable_channel(APP_GPTMR_DMA, APP_DMA_CH1);

    dma_reset(APP_GPTMR_DMA);

    intc_m_enable_irq_with_priority(APP_GPTMR_DMA_IRQ, 4);

    dma_default_channel_config(APP_GPTMR_DMA, &ch1_config);
    ch1_config.src_addr = (uint32_t)&(HPM_GPIO0->DI[GPIO_DI_GPIOE].VALUE);/* CAPPRD寄存器和CAPDTY寄存器是相邻的，一同传输64位就行 */
    ch1_config.dst_addr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)&gpio_read_data[0]);/* 目的地址同理，pwm_meas_table是64位的 */
    ch1_config.src_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;/* 只有接收到下一次请求，才搬运下一次数据 */
    ch1_config.src_width = DMA_TRANSFER_WIDTH_WORD;/* 源地址宽度 */
    ch1_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;/* 源地址不自增 */
    ch1_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;/* 一次触发搬运一次数据 */
    ch1_config.dst_width = DMA_TRANSFER_WIDTH_WORD;/* 目的地址宽度 */ 
    ch1_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;/* 目的地址自增 */
    ch1_config.dst_mode = DMA_HANDSHAKE_MODE_NORMAL;/* 普通模式 */
    ch1_config.size_in_byte = sizeof(gpio_read_data);

    ch1_config.priority = 0;

    if (status_success != dma_setup_channel(APP_GPTMR_DMA, APP_DMA_CH0, &ch1_config, false)) {
        printf(" dma setup channel failed 1\n");
        return;
    }

    dma_default_channel_config(APP_GPTMR_DMA, &ch0_config);
    ch0_config.src_addr = (uint32_t)&gpio_write_data;
    ch0_config.dst_addr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)&(HPM_GPIO0->DO[GPIO_DO_GPIOD].VALUE));
    ch0_config.src_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;
    ch0_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;
    ch0_config.src_width = DMA_TRANSFER_WIDTH_WORD;
    ch0_config.dst_width = DMA_TRANSFER_WIDTH_WORD;
    ch0_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;
    ch0_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
    ch0_config.dst_mode = DMA_HANDSHAKE_MODE_NORMAL;
    ch0_config.size_in_byte = sizeof(gpio_write_data);

    ch0_config.priority = 1;

    if (status_success != dma_setup_channel(APP_GPTMR_DMA, APP_DMA_CH1, &ch0_config, false)) {
        printf(" dma setup channel failed 2\n");
        return;
    }
    
}
#endif



void timer_config_us(GPTMR_Type * GPTMR,uint8_t ch_index,uint32_t priority,uint16_t us)
{
    uint32_t gptmr_freq;
    gptmr_channel_config_t config;
    uint32_t GPTMR_BASE_INDEX = (uint32_t)(GPTMR - HPM_GPTMR0_BASE);
    uint8_t GPTMR_Number = GPTMR_BASE_INDEX/0x4000;

    uint8_t ms_10 = 10;

    clock_name_t clock_name;
    switch(GPTMR_Number)
    {
        case 0:clock_name = clock_gptmr0; break;
        case 1:clock_name = clock_gptmr1; break;
        case 2:clock_name = clock_gptmr2; break;
        case 3:clock_name = clock_gptmr3; break;
        case 4:clock_name = clock_gptmr4; break;
        case 5:clock_name = clock_gptmr5; break;
        case 6:clock_name = clock_gptmr6; break;
        case 7:clock_name = clock_gptmr7; break;
    }

    gptmr_channel_get_default_config(GPTMR, &config);

    gptmr_freq = clock_get_frequency(clock_name);

    config.reload = gptmr_freq / 1000 * ms_10; /* reload整个周期为10ms */

    config.cmp[0] = config.reload - ((gptmr_freq / 1000000 * us)/2);/* 在周期的最后开始输出 */
    config.cmp_initial_polarity_high = true;

    gptmr_enable_cmp_output(GPTMR,ch_index);

    gptmr_enable_irq(GPTMR, GPTMR_CH_RLD_IRQ_MASK(ch_index));


    intc_m_enable_irq_with_priority((IRQn_GPTMR0+GPTMR_Number), priority);
    gptmr_channel_config(GPTMR, ch_index, &config, false);

}

void tick_us_isr(void)
{
    static uint8_t irq_count = 0;
    if (gptmr_check_status(HPM_GPTMR5, GPTMR_CH_RLD_STAT_MASK(2))) {
        gptmr_clear_status(HPM_GPTMR5, GPTMR_CH_RLD_STAT_MASK(2));
        pwm_stop_counter(HPM_PWM2);
        gptmr_stop_counter(HPM_GPTMR5, 2);
        pwm_output_over = true;
    }
}
SDK_DECLARE_EXT_ISR_M(IRQn_GPTMR5, tick_us_isr);
